Zadania

AdaGrad

  1. Rozszerz podany poniżej algorytm SGD o funkcjonalność algorytmu AdaGrad (włączana parametrem adaGrad=True). Zasady działania AdaGrad są podane w materiałach do wykładu.
    Uwaga: podczas dzielenia przez pierwastek sumy kwadratów historycznych gradientów warto dodać małą wartość $\epsilon=10^{-7}$ do mianownika (żeby nie dzielić przez 0).
  2. Wykorzystując dane z ostatnich ćwiczeń oraz algorytm AdaGrad, stwórz model wieloklasowej regresji logistycznej (dla wszystkich 10) z parametrami:
    • Rozmiar wsadu: 50
    • Liczba epok: 2
    • Rozmiar kroku $\alpha$: 1.0 (gdy używamy AdaGrad $\alpha$ może być niezmienne)
  • Oblicz jego jakość na zbiorze testowym. Następnie sprobuj uzyskać wynik podobny lub lepszy samym algorytmem SGD bez opcji AdaGrad, modyfikująć paramtr $\alpha$. Da się?

Walidacja Krzyżowa

  1. Na podstawie pseudo-kodu z wykładu zaimplementuj 5-krotną walidację krzyżową na danych uczących. Wykorzystaj średnią poprawność klasyfikacyjną z 5-ciu zbiorów walidacyjnych jako ocenę jakości na całym zbiorze uczącym.
  2. Dobierz na podstawie walidacji krzyżowej najlepsze parametry modelu (rozmiar wsadu, liczba epok, użycie SGD z/bez AdaGrad, paramtr $\alpha$), nie (!) patrząć na zbiór testowy.
  3. Sprawdź, czy tak dobrany model, po przetrenowaniu na całych danych jest również najlepszy na zbiorze testowym. (Nie ma niestety takiej gwarancji.)

Ensemble (za dodatkowe 20 punktów)

  1. Wytrenuj 10 klasyfikatorów z powyżej dobranymi parametrami tasujać dane trenujące przed każdym trenowaniem (pamiętaj by tasować odpowiedzi w tej samej kolejności!).
  2. Oblicz predykcje (klasy) dla każdego z nich na zbiorze testowym oraz jakość każdego klasyfikatora.
  3. Dla każdego przykłady wybierz klasę, która występowała najczęśćiej w odpowiedziach 10 klasyfikatorów jako nową klasę.
  4. Oblicz jakość tak uzyskanych predykcji i porównaj z jakością pojedynczych klasyfikatorów. Pomogło?



In [1]:
import numpy as np

def runningMeanFast(x, N):
    return np.convolve(x, np.ones((N,))/N, mode='valid')

def safeSigmoid(x, eps=0):
    y = 1.0/(1.0 + np.exp(-x))
    # przytnij od dolu i gory
    if eps > 0:
        y[y < eps] = eps
        y[y > 1 - eps] = 1 - eps
    return y

def h(theta, X, eps=0.0):
    return safeSigmoid(X*theta, eps)

def J(h,theta,X,y):
    m = len(y)
    f = h(theta, X, eps=10**-7)
    return -np.sum(np.multiply(y, np.log(f)) + 
                   np.multiply(1 - y, np.log(1 - f)), axis=0)/m

def dJ(h,theta,X,y):
    return 1.0/len(y)*(X.T*(h(theta,X)-y))

def softmax(X):
    return np.exp(X)/np.sum(np.exp(X))

In [2]:
def SGD(h, fJ, fdJ, theta, X, y, 
        alpha=0.001, maxEpochs=1.0, batchSize=100):
    m, n = X.shape
    start, end = 0, batchSize
    
    maxSteps = (m * float(maxEpochs)) / batchSize
    for i in range(int(maxSteps)):
        XBatch, yBatch =  X[start:end,:], y[start:end,:]

        theta = theta - alpha * fdJ(h, theta, XBatch, yBatch)
        
        if start + batchSize < m:
            start += batchSize
        else:
            start = 0
        end = min(start + batchSize, m)
        
    return theta

In [ ]: